// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/origin_trials/trial_token.h"

#include <memory>

#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebOriginTrialTokenStatus.h"
#include "url/gurl.h"

namespace content {

namespace {

    // This is a sample public key for testing the API. The corresponding private
    // key (use this to generate new samples for this test file) is:
    //
    //  0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13,
    //  0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba,
    //  0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75,
    //  0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a,
    //  0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64,
    //  0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0
    //
    //  This private key can also be found in tools/origin_trials/eftest.key in
    //  binary form. Please update that if changing the key.
    //
    //  To use this with a real browser, use --origin-trial-public-key with the
    //  public key, base-64-encoded:
    //  --origin-trial-public-key=dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=
    const uint8_t kTestPublicKey[] = {
        0x75,
        0x10,
        0xac,
        0xf9,
        0x3a,
        0x1c,
        0xb8,
        0xa9,
        0x28,
        0x70,
        0xd2,
        0x9a,
        0xd0,
        0x0b,
        0x59,
        0xe1,
        0xac,
        0x2b,
        0xb7,
        0xd5,
        0xca,
        0x1f,
        0x64,
        0x90,
        0x08,
        0x8e,
        0xa8,
        0xe0,
        0x56,
        0x3a,
        0x04,
        0xd0,
    };

    // This is a valid, but incorrect, public key for testing signatures against.
    // The corresponding private key is:
    //
    //  0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75,
    //  0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16,
    //  0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50,
    //  0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47,
    //  0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e,
    //  0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca
    const uint8_t kTestPublicKey2[] = {
        0x50,
        0x07,
        0x4d,
        0x76,
        0x55,
        0x56,
        0x42,
        0x17,
        0x2d,
        0x8a,
        0x9c,
        0x47,
        0x96,
        0x25,
        0xda,
        0x70,
        0xaa,
        0xb9,
        0xfd,
        0x53,
        0x5d,
        0x51,
        0x3e,
        0x16,
        0xab,
        0xb4,
        0x86,
        0xea,
        0xf3,
        0x35,
        0xc6,
        0xca,
    };

    // This is a good trial token, signed with the above test private key.
    // Generate this token with the command (in tools/origin_trials):
    // generate_token.py valid.example.com Frobulate --expire-timestamp=1458766277
    const char* kSampleToken = "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj"
                               "7FO5L22sNvkZZnacLvmfNwsAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
                               "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5"
                               "IjogMTQ1ODc2NjI3N30=";

    // This is a good subdomain trial token, signed with the above test private key.
    // Generate this token with the command (in tools/origin_trials):
    // generate_token.py example.com Frobulate --is-subdomain
    //   --expire-timestamp=1458766277
    const char* kSampleSubdomainToken = "Auu+j9nXAQoy5+t00MiWakZwFExcdNC8ENkRdK1gL4OMFHS0AbZCscslDTcP1fjN"
                                        "FjpbmQG+VCPk1NrldVXZng4AAABoeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxl"
                                        "LmNvbTo0NDMiLCAiaXNTdWJkb21haW4iOiB0cnVlLCAiZmVhdHVyZSI6ICJGcm9i"
                                        "dWxhdGUiLCAiZXhwaXJ5IjogMTQ1ODc2NjI3N30=";

    // This is a good trial token, explicitly not a subdomain, signed with the above
    // test private key. Generate this token with the command:
    // generate_token.py valid.example.com Frobulate --no-subdomain
    //   --expire-timestamp=1458766277
    const char* kSampleNonSubdomainToken = "AreD979D7tO0luSZTr1+/+J6E0SSj/GEUyLK41o1hXFzXw1R7Z1hCDHs0gXWVSu1"
                                           "lvH52Winvy39tHbsU2gJJQYAAABveyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
                                           "eGFtcGxlLmNvbTo0NDMiLCAiaXNTdWJkb21haW4iOiBmYWxzZSwgImZlYXR1cmUi"
                                           "OiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6IDE0NTg3NjYyNzd9";

    const char* kExpectedFeatureName = "Frobulate";
    const char* kExpectedOrigin = "https://valid.example.com";
    const char* kExpectedSubdomainOrigin = "https://example.com";
    const char* kExpectedMultipleSubdomainOrigin = "https://part1.part2.part3.example.com";
    const uint64_t kExpectedExpiry = 1458766277;

    // The token should not be valid for this origin, or for this feature.
    const char* kInvalidOrigin = "https://invalid.example.com";
    const char* kInsecureOrigin = "http://valid.example.com";
    const char* kIncorrectPortOrigin = "https://valid.example.com:444";
    const char* kIncorrectDomainOrigin = "https://valid.example2.com";
    const char* kInvalidTLDOrigin = "https://com";
    const char* kInvalidFeatureName = "Grokalyze";

    // The token should be valid if the current time is kValidTimestamp or earlier.
    double kValidTimestamp = 1458766276.0;

    // The token should be invalid if the current time is kInvalidTimestamp or
    // later.
    double kInvalidTimestamp = 1458766278.0;

    // Well-formed trial token with an invalid signature.
    const char* kInvalidSignatureToken = "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj"
                                         "7FO5L22sNvkZZnacLvmfNwsAAABaeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
                                         "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGV4IiwgImV4cGly"
                                         "eSI6IDE0NTg3NjYyNzd9";

    // Trial token truncated in the middle of the length field; too short to
    // possibly be valid.
    const char kTruncatedToken[] = "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj"
                                   "7FO5L22sNvkZZnacLvmfNwsA";

    // Trial token with an incorrectly-declared length, but with a valid signature.
    const char kIncorrectLengthToken[] = "Ao06eNl/CZuM88qurWKX4RfoVEpHcVHWxdOTrEXZkaC1GUHyb/8L4sthADiVWdc9"
                                         "kXFyF1BW5bbraqp6MBVr3wEAAABaeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
                                         "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5"
                                         "IjogMTQ1ODc2NjI3N30=";

    // Trial token with a misidentified version (42).
    const char kIncorrectVersionToken[] = "KlH8wVLT5o59uDvlJESorMDjzgWnvG1hmIn/GiT9Ng3f45ratVeiXCNTeaJheOaG"
                                          "A6kX4ir4Amv8aHVC+OJHZQkAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
                                          "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5"
                                          "IjogMTQ1ODc2NjI3N30=";

    const char kSampleTokenJSON[] = "{\"origin\": \"https://valid.example.com:443\", \"feature\": "
                                    "\"Frobulate\", \"expiry\": 1458766277}";

    const char kSampleNonSubdomainTokenJSON[] = "{\"origin\": \"https://valid.example.com:443\", \"isSubdomain\": false, "
                                                "\"feature\": \"Frobulate\", \"expiry\": 1458766277}";

    const char kSampleSubdomainTokenJSON[] = "{\"origin\": \"https://example.com:443\", \"isSubdomain\": true, "
                                             "\"feature\": \"Frobulate\", \"expiry\": 1458766277}";

    // Various ill-formed trial tokens. These should all fail to parse.
    const char* kInvalidTokens[] = {
        // Invalid - Not JSON at all
        "abcde",
        // Invalid JSON
        "{",
        // Not an object
        "\"abcde\"",
        "123.4",
        "[0, 1, 2]",
        // Missing keys
        "{}",
        "{\"something\": 1}",
        "{\"origin\": \"https://a.a\"}",
        "{\"origin\": \"https://a.a\", \"feature\": \"a\"}",
        "{\"origin\": \"https://a.a\", \"expiry\": 1458766277}",
        "{\"feature\": \"FeatureName\", \"expiry\": 1458766277}",
        // Incorrect types
        "{\"origin\": 1, \"feature\": \"a\", \"expiry\": 1458766277}",
        "{\"origin\": \"https://a.a\", \"feature\": 1, \"expiry\": 1458766277}",
        "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": \"1\"}",
        "{\"origin\": \"https://a.a\", \"isSubdomain\": \"true\", \"feature\": "
        "\"a\", \"expiry\": 1458766277}",
        "{\"origin\": \"https://a.a\", \"isSubdomain\": 1, \"feature\": \"a\", "
        "\"expiry\": 1458766277}",
        // Negative expiry timestamp
        "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": -1}",
        // Origin not a proper origin URL
        "{\"origin\": \"abcdef\", \"feature\": \"a\", \"expiry\": 1458766277}",
        "{\"origin\": \"data:text/plain,abcdef\", \"feature\": \"a\", \"expiry\": "
        "1458766277}",
        "{\"origin\": \"javascript:alert(1)\", \"feature\": \"a\", \"expiry\": "
        "1458766277}",
    };

} // namespace

class TrialTokenTest : public testing::TestWithParam<const char*> {
public:
    TrialTokenTest()
        : expected_origin_(GURL(kExpectedOrigin))
        , expected_subdomain_origin_(GURL(kExpectedSubdomainOrigin))
        , expected_multiple_subdomain_origin_(
              GURL(kExpectedMultipleSubdomainOrigin))
        , invalid_origin_(GURL(kInvalidOrigin))
        , insecure_origin_(GURL(kInsecureOrigin))
        , incorrect_port_origin_(GURL(kIncorrectPortOrigin))
        , incorrect_domain_origin_(GURL(kIncorrectDomainOrigin))
        , invalid_tld_origin_(GURL(kInvalidTLDOrigin))
        , expected_expiry_(base::Time::FromDoubleT(kExpectedExpiry))
        , valid_timestamp_(base::Time::FromDoubleT(kValidTimestamp))
        , invalid_timestamp_(base::Time::FromDoubleT(kInvalidTimestamp))
        , correct_public_key_(
              base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey),
                  arraysize(kTestPublicKey)))
        , incorrect_public_key_(
              base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey2),
                  arraysize(kTestPublicKey2)))
    {
    }

protected:
    blink::WebOriginTrialTokenStatus Extract(const std::string& token_text,
        base::StringPiece public_key,
        std::string* token_payload)
    {
        return TrialToken::Extract(token_text, public_key, token_payload);
    }

    blink::WebOriginTrialTokenStatus ExtractIgnorePayload(
        const std::string& token_text,
        base::StringPiece public_key)
    {
        std::string token_payload;
        return Extract(token_text, public_key, &token_payload);
    }

    std::unique_ptr<TrialToken> Parse(const std::string& token_payload)
    {
        return TrialToken::Parse(token_payload);
    }

    bool ValidateOrigin(TrialToken* token, const url::Origin origin)
    {
        return token->ValidateOrigin(origin);
    }

    bool ValidateFeatureName(TrialToken* token, const char* feature_name)
    {
        return token->ValidateFeatureName(feature_name);
    }

    bool ValidateDate(TrialToken* token, const base::Time& now)
    {
        return token->ValidateDate(now);
    }

    base::StringPiece correct_public_key() { return correct_public_key_; }
    base::StringPiece incorrect_public_key() { return incorrect_public_key_; }

    const url::Origin expected_origin_;
    const url::Origin expected_subdomain_origin_;
    const url::Origin expected_multiple_subdomain_origin_;
    const url::Origin invalid_origin_;
    const url::Origin insecure_origin_;
    const url::Origin incorrect_port_origin_;
    const url::Origin incorrect_domain_origin_;
    const url::Origin invalid_tld_origin_;

    const base::Time expected_expiry_;
    const base::Time valid_timestamp_;
    const base::Time invalid_timestamp_;

private:
    base::StringPiece correct_public_key_;
    base::StringPiece incorrect_public_key_;
};

// Test the extraction of the signed payload from token strings. This includes
// checking the included version identifier, payload length, and cryptographic
// signature.

// Test verification of signature and extraction of token JSON from signed
// token.
TEST_F(TrialTokenTest, ValidateValidSignature)
{
    std::string token_payload;
    blink::WebOriginTrialTokenStatus status = Extract(kSampleToken, correct_public_key(), &token_payload);
    ASSERT_EQ(blink::WebOriginTrialTokenStatus::Success, status);
    EXPECT_STREQ(kSampleTokenJSON, token_payload.c_str());
}

TEST_F(TrialTokenTest, ValidateSubdomainValidSignature)
{
    std::string token_payload;
    blink::WebOriginTrialTokenStatus status = Extract(kSampleSubdomainToken, correct_public_key(), &token_payload);
    ASSERT_EQ(blink::WebOriginTrialTokenStatus::Success, status);
    EXPECT_STREQ(kSampleSubdomainTokenJSON, token_payload.c_str());
}

TEST_F(TrialTokenTest, ValidateNonSubdomainValidSignature)
{
    std::string token_payload;
    blink::WebOriginTrialTokenStatus status = Extract(kSampleNonSubdomainToken, correct_public_key(), &token_payload);
    ASSERT_EQ(blink::WebOriginTrialTokenStatus::Success, status);
    EXPECT_STREQ(kSampleNonSubdomainTokenJSON, token_payload.c_str());
}

TEST_F(TrialTokenTest, ValidateInvalidSignature)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload(kInvalidSignatureToken, correct_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::InvalidSignature, status);
}

TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectKey)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload(kSampleToken, incorrect_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::InvalidSignature, status);
}

TEST_F(TrialTokenTest, ValidateEmptyToken)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload("", correct_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Malformed, status);
}

TEST_F(TrialTokenTest, ValidateShortToken)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload(kTruncatedToken, correct_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Malformed, status);
}

TEST_F(TrialTokenTest, ValidateUnsupportedVersion)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload(kIncorrectVersionToken, correct_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongVersion, status);
}

TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectLength)
{
    blink::WebOriginTrialTokenStatus status = ExtractIgnorePayload(kIncorrectLengthToken, correct_public_key());
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Malformed, status);
}

// Test parsing of fields from JSON token.

TEST_F(TrialTokenTest, ParseEmptyString)
{
    std::unique_ptr<TrialToken> empty_token = Parse("");
    EXPECT_FALSE(empty_token);
}

TEST_P(TrialTokenTest, ParseInvalidString)
{
    std::unique_ptr<TrialToken> empty_token = Parse(GetParam());
    EXPECT_FALSE(empty_token) << "Invalid trial token should not parse.";
}

INSTANTIATE_TEST_CASE_P(, TrialTokenTest, ::testing::ValuesIn(kInvalidTokens));

TEST_F(TrialTokenTest, ParseValidToken)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_EQ(kExpectedFeatureName, token->feature_name());
    EXPECT_FALSE(token->match_subdomains());
    EXPECT_EQ(expected_origin_, token->origin());
    EXPECT_EQ(expected_expiry_, token->expiry_time());
}

TEST_F(TrialTokenTest, ParseValidNonSubdomainToken)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleNonSubdomainTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_EQ(kExpectedFeatureName, token->feature_name());
    EXPECT_FALSE(token->match_subdomains());
    EXPECT_EQ(expected_origin_, token->origin());
    EXPECT_EQ(expected_expiry_, token->expiry_time());
}

TEST_F(TrialTokenTest, ParseValidSubdomainToken)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleSubdomainTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_EQ(kExpectedFeatureName, token->feature_name());
    EXPECT_TRUE(token->match_subdomains());
    EXPECT_EQ(kExpectedSubdomainOrigin, token->origin().Serialize());
    EXPECT_EQ(expected_subdomain_origin_, token->origin());
    EXPECT_EQ(expected_expiry_, token->expiry_time());
}

TEST_F(TrialTokenTest, ValidateValidToken)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_TRUE(ValidateOrigin(token.get(), expected_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), invalid_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), insecure_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), incorrect_port_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), incorrect_domain_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), invalid_tld_origin_));
    EXPECT_TRUE(ValidateFeatureName(token.get(), kExpectedFeatureName));
    EXPECT_FALSE(ValidateFeatureName(token.get(), kInvalidFeatureName));
    EXPECT_FALSE(ValidateFeatureName(
        token.get(), base::ToUpperASCII(kExpectedFeatureName).c_str()));
    EXPECT_FALSE(ValidateFeatureName(
        token.get(), base::ToLowerASCII(kExpectedFeatureName).c_str()));
    EXPECT_TRUE(ValidateDate(token.get(), valid_timestamp_));
    EXPECT_FALSE(ValidateDate(token.get(), invalid_timestamp_));
}

TEST_F(TrialTokenTest, ValidateValidSubdomainToken)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleSubdomainTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_TRUE(ValidateOrigin(token.get(), expected_origin_));
    EXPECT_TRUE(ValidateOrigin(token.get(), expected_subdomain_origin_));
    EXPECT_TRUE(ValidateOrigin(token.get(), expected_multiple_subdomain_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), insecure_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), incorrect_port_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), incorrect_domain_origin_));
    EXPECT_FALSE(ValidateOrigin(token.get(), invalid_tld_origin_));
}

TEST_F(TrialTokenTest, TokenIsValid)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Success,
        token->IsValid(expected_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(invalid_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(insecure_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(incorrect_port_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Expired,
        token->IsValid(expected_origin_, invalid_timestamp_));
}

TEST_F(TrialTokenTest, SubdomainTokenIsValid)
{
    std::unique_ptr<TrialToken> token = Parse(kSampleSubdomainTokenJSON);
    ASSERT_TRUE(token);
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Success,
        token->IsValid(expected_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Success,
        token->IsValid(expected_subdomain_origin_, valid_timestamp_));
    EXPECT_EQ(
        blink::WebOriginTrialTokenStatus::Success,
        token->IsValid(expected_multiple_subdomain_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(incorrect_domain_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(insecure_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::WrongOrigin,
        token->IsValid(incorrect_port_origin_, valid_timestamp_));
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Expired,
        token->IsValid(expected_origin_, invalid_timestamp_));
}

// Test overall extraction, to ensure output status matches returned token
TEST_F(TrialTokenTest, ExtractValidToken)
{
    blink::WebOriginTrialTokenStatus status;
    std::unique_ptr<TrialToken> token = TrialToken::From(kSampleToken, correct_public_key(), &status);
    EXPECT_TRUE(token);
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Success, status);
}

TEST_F(TrialTokenTest, ExtractInvalidSignature)
{
    blink::WebOriginTrialTokenStatus status;
    std::unique_ptr<TrialToken> token = TrialToken::From(kSampleToken, incorrect_public_key(), &status);
    EXPECT_FALSE(token);
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::InvalidSignature, status);
}

TEST_F(TrialTokenTest, ExtractMalformedToken)
{
    blink::WebOriginTrialTokenStatus status;
    std::unique_ptr<TrialToken> token = TrialToken::From(kIncorrectLengthToken, correct_public_key(), &status);
    EXPECT_FALSE(token);
    EXPECT_EQ(blink::WebOriginTrialTokenStatus::Malformed, status);
}

} // namespace content
